#!/usr/bin/python
#coding=utf-8
import Queue
import threading
from   lib.Scan import *
from   lib.MongoTesting import *
from   lib.Curlgit import *
from   lib.RedisTesting import *
import time
import optparse
import sys

class Fscan:
    def __init__(self,host_file_path,thread_counts=1,out_file_path='outfile.txt'):
        self.host_queue=Queue.Queue()
        self.host_port=Queue.Queue()
        self.t=threading
        self.thread_counts=thread_counts
        self.host_file=open(host_file_path)
        self.log_file=open('log.txt','w')
        self.out_file=open(out_file_path,'w')
        self.lock = threading.Lock()
        self.active_thread=thread_counts
        self.www_exp={"GitTesting"}
        self.scan_num=0
        #self.ip_exp={"GitTesting":[80,8080],"MongoTesting":[27017],"RedisTesting":[6379]}
        self.ip_exp={"GitTesting":[80,8080],"RedisTesting":[6379],,"MongoTesting":[27017]}
        self.exp_port=[]
    #读文件 添加到队列
    def _readfile(self):
        while True:
            lin=self.host_file.readline().strip()
            if lin:
                self.host_queue.put(lin)
            else:
                break
    #为scan设置端口
    def _set_port(self):
    
        for p in self.ip_exp.values():
            self.exp_port+=p
        #去掉重复
        self.exp_port= list(set(self.exp_port))
        #print self.exp_port

    
    def _print_ms(self,con):
        # 写日志文件
        self.log_file.write(con+'\n')
        if con[1] != '-':
            self.lock.acquire()
            print con
            self.lock.release()
            self.out_file.write(con+'\n')
    
    #实时打印进度
    def _print_progess(self):
        
        self.lock.acquire()
        self.scan_num+=1
        
        if self.scan_num/(self.host_num*1.00)==1:
           msg='Wait  for  all  threads  exit '
        else:
           msg='Scanned  %.2f%% in %.2f s'%(self.scan_num/(self.host_num*1.00)*100,(time.time()-self.start_time))
        sys.stdout.write(msg+'\r')
        sys.stdout.flush()
        self.lock.release()
    #扫描端口
    def _scan_port(self):
        while True:
            try:
                host_port =Scanport().run(self.host_queue.get(1,0),self.exp_port)
                self._print_progess()
                if host_port.items()[0][1]:
                   # {'114.114.114.114': {'114.114.114.114': None}} 只put 114.114.114.114
                    if   host_port.items()[0][0] == host_port.items()[0][1].keys()[0] and host_port.items()[0][1].items()[0][1] != None:
                        self.host_port.put(host_port.items()[0][1])
                        #print host_port.items()[0][1]
                    #{'help.10010.com': {'123.125.96.211': [80, 8080]}} put 两个    
                    elif host_port.items()[0][0] != host_port.items()[0][1].keys()[0] and  host_port.items()[0][1].items()[0][1] != None:
                        self.host_port.put(host_port.items()[0][1])
                        self.host_port.put(host_port.items()[0][0])
                    #{'s1.bb.05wan.com': {'60.191.205.159': None}} put s1.bb.05wan.com
                    elif host_port.items()[0][0] !=  host_port.items()[0][1].keys()[0] and   host_port.items()[0][1].items()[0][1] == None:
                        self.host_port.put(host_port.items()[0][0]) 
                        self._print_ms('[-] : %s port close'%host_port.items()[0][1].keys()[0])
                       
                else:
                    self._print_ms('[-] : %s not found'%host_port.items()[0][0])
                    
            except Queue.Empty:
                self.lock.acquire()
                self.active_thread-=1
                self.lock.release()
                break
    #尝试exp
    def _testing(self):
        while True:
            try:
                host_port=self.host_port.get(1,5)
                
                # www exp
                if type('str')==type(host_port):
                    for exp in self.www_exp:
                        exec("res="+exp+"().run('"+host_port+"')")
                        [self._print_ms(r) for r in res]
                # ip exp
                else:
                    #print host_port
                    for (exp,port) in self.ip_exp.items():
                        port = [p for p in host_port.values()[0] if p in port]
                        if port:
                           
                            exec("res="+exp+"().run("+str({host_port.keys()[0]:port})+")")
                            #print res
                            [self._print_ms(r) for r in res]
                    
            except Queue.Empty:
                if self.active_thread==0:break
                #else:pass
                
    def run(self):
        
        self.start_time=time.time()
        self._print_ms("Starting Fscan at %s"%time.asctime( time.localtime(time.time())))
        self._set_port()
        threadsread=[]
        threadscanport=[]
        threadtesting=[]

        # strat readfile
        [threadsread.append(self.t.Thread(target=self._readfile)) for i in range(self.thread_counts)]
        [t.start() for t in threadsread ] and [t.join() for t in threadsread]
        self.host_num=self.host_queue.qsize()

        self._print_ms("Hostfile: %s lines \n"%self.host_num)

        # start scan port 
        [threadscanport.append(self.t.Thread(target=self._scan_port)) for i in range(self.thread_counts)]
        [t.start() for t in threadscanport] 

        # start testing
        [threadtesting.append(self.t.Thread(target=self._testing)) for i in range(self.thread_counts)]
        [t.start() for t in threadtesting ] and  [t.join() for t in threadtesting ]

        self.end_time=time.time()

        self._print_ms('\n\nFscan done : scan in %fs'%(self.end_time - self.start_time))
if __name__ == '__main__':
    
    parser=optparse.OptionParser('usage: %prog [options] -f filename')
    parser.add_option('-t', '--threads', dest='threads_num',default=50, type='int',help='Number of threads. default = 50.')
    parser.add_option('-f', '--filename', dest='filename', default=None, type='string',help='Host file name. ')
    parser.add_option('-o', '--output', dest='output', default='outfile.txt',type='string', help='Output file name. default = outfile.txt.')

    (options, args) = parser.parse_args()
    
    if not options.filename: parser.print_help()
    else:
        F=Fscan(
            host_file_path=options.filename,
            thread_counts=options.threads_num,
            out_file_path=options.output
        )
        F.run()
    
    # F=Fscan("h://11.txt")
    # F.run()